package com.school.admin.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.school.admin.common.config.SystemConfig;
import com.school.admin.common.handler.GlobalException;
import com.school.admin.common.handler.GlobalExceptionEnum;
import com.school.admin.common.result.BaseResult;
import com.school.admin.common.result.R;
import com.school.admin.common.result.RedisKeyResult;
import com.school.admin.common.utils.ConversionParametersUtils;
import com.school.admin.common.utils.MD5Util;
import com.school.admin.common.utils.RedisUtil;
import com.school.admin.common.utils.UserLogInfoDto;
import com.school.admin.entity.MallMenuRole;
import com.school.admin.entity.MallSysRoleUser;
import com.school.admin.entity.MallSysUser;
import com.school.admin.entity.vo.MallMenuVo;
import com.school.admin.entity.vo.MallSysUserQueryVo;
import com.school.admin.entity.vo.MallSysUserVo;
import com.school.admin.mapper.MallMenuRoleMapper;
import com.school.admin.mapper.MallSysUserMapper;
import com.school.admin.service.MallMenuRoleService;
import com.school.admin.service.MallMenuService;
import com.school.admin.service.MallSysRoleUserService;
import com.school.admin.service.MallSysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author sunpx
 * @since 2022-03-24
 */
@SuppressWarnings("ALL")
@Service
public class MallSysUserServiceImpl extends ServiceImpl<MallSysUserMapper, MallSysUser> implements MallSysUserService {


    @Autowired
    RedisUtil redisUtil;

    @Resource
    private MallMenuRoleMapper mallMenuRoleMapper;

    @Autowired
    MallMenuRoleService mallMenuRoleService;

    @Autowired
    private MallMenuService mallMenuService;

    @Autowired
    private MallSysRoleUserService mallSysRoleUserService;

    @Override
    public Map login(MallSysUser user, HttpServletRequest request, Long singFailTime) {
        QueryWrapper<MallSysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", user.getUsername());
        MallSysUser userBs = baseMapper.selectOne(queryWrapper);
        if (userBs == null) {
            throw new GlobalException(GlobalExceptionEnum.LOGIN_FAILED.getCode(), "无此用户");
        }


        String loginKeyTime = BaseResult.RedisKeyResult.WRONG_LOGIN_TIME + userBs.getId();
        String loginKey = BaseResult.RedisKeyResult.WRONG_LOGIN + userBs.getId();
        if (RedisKeyResult.redisUtil.hasKey(loginKeyTime)) {
            long expire = RedisKeyResult.redisUtil.getExpire(loginKeyTime, TimeUnit.SECONDS);
            if (expire>1) {
                long h = expire/3600;
                long m = (expire%3600)/60;
                long s = (expire%3600)%60;
                throw new GlobalException(GlobalExceptionEnum.LOGIN_TOO_MANY_ERRORS.getCode(), "您尝试次数过高请" + h+"小时"+m+"分钟"+s + "秒后重试");
            }
        }



        //验证登录
        R verification = MD5Util.verification(userBs.getPassword(), userBs.getSalt(), user.getPassword(), userBs.getId());
        if (verification.getSuccess()==false){
            throw new GlobalException(verification.getCode(),verification.getMessage());
        }
        RedisKeyResult.redisUtil.delete(loginKeyTime,loginKey);

        //返还结果
        Map<String, Object> map = new HashMap<>();

        //过滤敏感信息
        userBs.setPassword("");
        userBs.setSalt("");
        map.put("userInfo", userBs);

        // TODO 查询用户角色
        String byUserId = mallMenuRoleMapper.getByUserId(String.valueOf(userBs.getId()));

        // TODO 查询菜单信息
        List<MallMenuVo> listMode = mallMenuService.getListMode(byUserId);
        // TODO 按钮数据
        String listModeBtn = mallMenuService.getListModeBtn(byUserId);
        // TODO 返还数据
        map.put("modul", listMode);

        map.put("btn", listModeBtn);

        String uuid = IdUtil.simpleUUID();

        // TODO 生成json字符串 放签名
        String s = JSONUtil.toJsonStr(new UserLogInfoDto()
                .setUserId(String.valueOf(userBs.getId()))
                .setEmail(userBs.getEmail()).setRoleId(byUserId)
                .setUsername(userBs.getUsername()).setLoginKey(uuid)
        );
        map.put("sign",
                ConversionParametersUtils
                        .generateSign(SystemConfig.loginExpirationTime*1000, s, String.valueOf(userBs.getId())));
        redisUtil.hset(BaseResult.RedisKeyResult.USER_LOGIN, BaseResult.RedisKeyResult.USER_LOGIN_KEY + userBs.getId(), s, singFailTime);





        if (SystemConfig.uniqueLogin){
            redisUtil.set(BaseResult.RedisKeyResult.LOGIN_AUTHENTICATION+userBs.getId(),uuid, SystemConfig.loginExpirationTime * 1000);
        }


        return map;
    }


    @Override
    public IPage queryPage(MallSysUserQueryVo mallSysUser) {
        IPage<MallSysUserVo> mallSysUserVoIPage = baseMapper.queryPage(mallSysUser.getPage(), mallSysUser);
        List<MallSysUserVo> records = mallSysUserVoIPage.getRecords();
        records.forEach(res -> {
            String roleName = res.getRoleName();
            if (!StringUtils.isEmpty(roleName)) {
                res.setRoleNameList(Arrays.asList(res.getRoleName().split(",")));
            }
        });
        mallSysUserVoIPage.setRecords(records);
        return mallSysUserVoIPage;
    }

    @Override
    public void uptUser(MallSysUser user) {
        boolean b = saveOrUpdate(user);
        if (!b) {
            throw new GlobalException(GlobalExceptionEnum.SAVE_FAILED.getCode(), "更新失败");
        }
    }

    @Override
    @Transactional
    public void addUser(MallSysUserVo user) {

        boolean name = isName(user.getUsername());
        if (!name && StringUtils.isEmpty(user.getId())) {
            throw new GlobalException(GlobalExceptionEnum.SAVE_FAILED.getCode(), "用户名重复");
        }

        if (StringUtils.isEmpty(user.getSalt())) {
            Map<String, String> map = MD5Util.encryptionPass(user.getPassword());
            user.setPassword(map.get("password"));
            user.setSalt(map.get("salt"));
            user.setGmtCreate(new Date());
        }


        boolean save = saveOrUpdate(user);
        // TODO 插入角色
        saveUserRole(user);
        if (!save) {
            throw new GlobalException(GlobalExceptionEnum.SAVE_FAILED.getCode(), "保存失败");
        }
    }


    @Override
    public void uptUserInfo(MallSysUserVo mallSysUser, MallSysUser one) {
        if (one != null && !(one.getId().equals(mallSysUser.getId()))) {
            throw new GlobalException(50001, "用户名重复");
        }

        mallSysUser.setPassword(one.getPassword()).setSalt(one.getSalt());

        UpdateWrapper<MallSysRoleUser> mallSysRoleUserUpdateWrapper = new UpdateWrapper<>();
        mallSysRoleUserUpdateWrapper.eq("user_id",mallSysUser.getId());
        mallSysRoleUserService.remove(mallSysRoleUserUpdateWrapper);

        //插入中间表
        saveUserRole(mallSysUser);
        //更新消息
        saveOrUpdate(mallSysUser);
    }

    /**
     * 插入中间表
     * @param user
     */
    @Override
    @Transactional
    public void saveUserRole(MallSysUserVo user) {
        List<String> roleIds = user.getRoleId();
        if (CollectionUtils.isEmpty(roleIds)) {
            throw new GlobalException(500, "请选择角色");
        }
        List<MallSysRoleUser> roleUserList = new ArrayList<>();
        for (String roleId : roleIds) {
            roleUserList.add(new MallSysRoleUser().setUserId(user.getId()).setRoleId(Long.valueOf(roleId)));
        }
        mallSysRoleUserService.saveBatch(roleUserList);
    }


    @Override
    public boolean isName(String name) {
        QueryWrapper<MallSysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", name);
        int count = count(queryWrapper);
        if (count == 0) {
            return true;
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delUser(String id) {
        QueryWrapper<MallMenuRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("menu_code", id);
        mallMenuRoleService.remove(queryWrapper);
        return removeById(id);
    }

    @Override
    public Map<String, Object> userDetail(String id) {
        HashMap<String, Object> returnTotalMap = new HashMap<>();
        MallSysUserVo byId1 = baseMapper.getUserInfo(id);
        byId1.setPassword(null).setSalt(null);
        String roleName = byId1.getRoleName();
        if (!StringUtils.isEmpty(roleName)) {
            byId1.setRoleId(Arrays.asList(roleName.split(",")));
        }

        returnTotalMap.put("userInfoAll", byId1);
        return returnTotalMap;
    }


}
